package vip.xiaonuo.biz.modular.wechat.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.transferbatch.TransferBatchService;
import com.wechat.pay.java.service.transferbatch.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.modular.wechat.constant.WechatConstant;
import vip.xiaonuo.biz.modular.wechat.domain.dto.WechatCommissionDTO;
import vip.xiaonuo.biz.modular.wechat.domain.resp.WechatTransferQueryDetailResp;
import vip.xiaonuo.biz.modular.wechat.domain.resp.WechatTransferResp;
import vip.xiaonuo.biz.modular.wechat.service.WechatTransferService;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.util.OkHttpUtils;

import java.util.List;

/**
 * @author hjl
 */
@Slf4j
@Service("wechatTransferService")
public class WechatTransferServiceImpl implements WechatTransferService {
    @Value(value = "${transfer.appId}")
    private String appId;
    @Value(value = "${transfer.appSecret}")
    private String appSecret;
    @Value(value = "${transfer.merchantId}")
    private String merchantId;
    @Value(value = "${transfer.privateKeyPath}")
    private String privateKeyPath;
    @Value(value = "${transfer.merchantSerialNumber}")
    private String merchantSerialNumber;
    @Value(value = "${transfer.wechatPayCertificatePath}")
    private String wechatPayCertificatePath;

    private static String REDIS_TOKEN_KEY = "wechat_applet_token_key";
    private static String UNLIMITED_QRCODE = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";

    private static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";


    public static TransferBatchService transferBatchService;

    @Override
    public WechatTransferResp transfer(WechatCommissionDTO wechatCommissionDTO){
        WechatTransferResp resp = new WechatTransferResp();
        RSAConfig config = new RSAConfig.Builder().merchantId(merchantId)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .wechatPayCertificatesFromPath(wechatPayCertificatePath)
                .build();
        transferBatchService = new TransferBatchService.Builder().config(config).build();
        InitiateBatchTransferRequest initiateBatchTransferRequest = new InitiateBatchTransferRequest();
        // 商户appid
        initiateBatchTransferRequest.setAppid(appId);
        // 商家批次单号
        initiateBatchTransferRequest.setOutBatchNo(wechatCommissionDTO.getRewardNo());
        // 批次名称
        initiateBatchTransferRequest.setBatchName(DateUtil.today()+"奖励发放");
        // 批次备注 最多允许32个字符
        initiateBatchTransferRequest.setBatchRemark(DateUtil.today()+"奖励发放");

        // 转账明细
        List<TransferDetailInput> transferDetailListList = CollectionUtil.newArrayList();
        TransferDetailInput transferDetailInput = new TransferDetailInput();
        // 商家明细单号
        transferDetailInput.setOutDetailNo(wechatCommissionDTO.getRewardNo());
        // 转账金额 转账金额单位为“分”
        transferDetailInput.setTransferAmount(wechatCommissionDTO.getCommissionAmount());
        // 收款用户openid
        transferDetailInput.setOpenid(wechatCommissionDTO.getOpenId());
        // 转账备注
        transferDetailInput.setTransferRemark("任务奖励");
        transferDetailListList.add(transferDetailInput);
        initiateBatchTransferRequest.setTransferDetailList(transferDetailListList);

        // 转账总金额 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致，否则无法发起转账操作
        initiateBatchTransferRequest.setTotalAmount(wechatCommissionDTO.getCommissionAmount());
        // 转账总笔数 一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致，否则无法发起转账操作
        initiateBatchTransferRequest.setTotalNum(1);

        //转账返回信息处理
        try {
            InitiateBatchTransferResponse response = transferBatchService.initiateBatchTransfer(initiateBatchTransferRequest);
            resp.setCode(WechatConstant.RESP_SUCCESS_CODE_200);
            resp.setMessage(WechatConstant.RESP_SUCCESS_MSG);
            resp.setBatchId(response.getBatchId());
        } catch (ServiceException e) {
            log.error("==wechatTransfer==",e);
            resp.setCode(e.getErrorCode());
            resp.setMessage(e.getMessage());
        }
        return resp;
    }

    @Override
    public WechatTransferResp transferBatch(WechatCommissionDTO wechatCommissionDTO){
        WechatTransferResp resp = new WechatTransferResp();
        RSAConfig config = new RSAConfig.Builder().merchantId(merchantId)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .wechatPayCertificatesFromPath(wechatPayCertificatePath)
                .build();
        transferBatchService = new TransferBatchService.Builder().config(config).build();
        InitiateBatchTransferRequest initiateBatchTransferRequest = new InitiateBatchTransferRequest();
        // 商户appid
        initiateBatchTransferRequest.setAppid(appId);
        // 商家批次单号
        initiateBatchTransferRequest.setOutBatchNo(wechatCommissionDTO.getRewardNo());
        // 批次名称
        initiateBatchTransferRequest.setBatchName(DateUtil.today()+"红包发放");
        // 批次备注 最多允许32个字符
        initiateBatchTransferRequest.setBatchRemark(DateUtil.today()+"红包发放");

        // 转账明细
        List<TransferDetailInput> transferDetailListList = CollectionUtil.newArrayList();
        Long countall=0L;
        for (int i = 0; i <wechatCommissionDTO.getOpenIdList().size() ; i++) {
            TransferDetailInput transferDetailInput = new TransferDetailInput();
            // 商家明细单号
            transferDetailInput.setOutDetailNo(wechatCommissionDTO.getRewardNo()+i);
            // 转账金额 转账金额单位为“分”
            transferDetailInput.setTransferAmount(wechatCommissionDTO.getCommissionAmount());
            // 收款用户openid
            transferDetailInput.setOpenid(wechatCommissionDTO.getOpenIdList().get(i));
            // 转账备注
            transferDetailInput.setTransferRemark("红包奖励");
            transferDetailListList.add(transferDetailInput);
            countall+=wechatCommissionDTO.getCommissionAmount();
        }

        initiateBatchTransferRequest.setTransferDetailList(transferDetailListList);

        // 转账总金额 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致，否则无法发起转账操作
        initiateBatchTransferRequest.setTotalAmount(countall);
        // 转账总笔数 一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致，否则无法发起转账操作
        initiateBatchTransferRequest.setTotalNum(wechatCommissionDTO.getOpenIdList().size());

        //转账返回信息处理
        try {
            InitiateBatchTransferResponse response = transferBatchService.initiateBatchTransfer(initiateBatchTransferRequest);
            resp.setCode(WechatConstant.RESP_SUCCESS_CODE_200);
            resp.setMessage(WechatConstant.RESP_SUCCESS_MSG);
            resp.setBatchId(response.getBatchId());
        } catch (ServiceException e) {
            log.error("==wechatTransfer==",e);
            resp.setCode(e.getErrorCode());
            resp.setMessage(e.getMessage());
        }
        return resp;
    }

    @Override
    public String getAppletQrcode(String sceneCode) {
        String respStr = "";
        // 取微信accessToken
        String accessToken = this.getAccessToken();
        // 根据场景值生成小程序二维码
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("scene",sceneCode);
        // 调用小程序生成二维码接口生成二维码
        try {
            respStr = OkHttpUtils.httpPostWechatApplet(String.format(UNLIMITED_QRCODE,accessToken),jsonObject.toJSONString());
            System.out.println("getAppletQrcode===="+respStr);
        } catch (Exception e) {
            log.error("==getAccessToken==",e.getMessage());
        }
        return respStr;
    }


    @Override
    public WechatTransferQueryDetailResp queryDetail(String rewardNo) {
        WechatTransferQueryDetailResp resp = new WechatTransferQueryDetailResp();

        RSAConfig config = new RSAConfig.Builder().merchantId(merchantId)
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(merchantSerialNumber)
                .wechatPayCertificatesFromPath(wechatPayCertificatePath)
                .build();
        transferBatchService = new TransferBatchService.Builder().config(config).build();
        GetTransferDetailByOutNoRequest request = new GetTransferDetailByOutNoRequest();
        request.setOutBatchNo(rewardNo);
        request.setOutDetailNo(rewardNo);

        try {
            TransferDetailEntity response = transferBatchService.getTransferDetailByOutNo(request);
            resp.setCode(WechatConstant.RESP_SUCCESS_CODE_200);
            resp.setMessage(WechatConstant.RESP_SUCCESS_MSG);
            resp.setDetailStatus(response.getDetailStatus());
            if(ObjectUtil.isNotEmpty(response.getFailReason())){
                resp.setFailReason(response.getFailReason().name());
            }else{
                resp.setFailReason("");
            }
            resp.setUpdateTime(response.getUpdateTime());
        } catch (ServiceException e) {
            log.error(e.getErrorCode()+"===queryDetailResp=="+e.getErrorMessage());
            resp.setCode(e.getErrorCode());
            resp.setMessage(e.getErrorMessage());
        }
        return resp;
    }

    private String getAccessToken(){
        JSONObject jsonObject = null;
        try {
            String respStr = OkHttpUtils.httpGet(String.format(ACCESS_TOKEN_URL, appId, appSecret));
            jsonObject = JSONObject.parseObject(respStr);
        } catch (Exception e) {
            log.error("==getAccessToken==",e.getMessage());
        }

        if(ObjectUtil.isEmpty(jsonObject)){
            throw new CommonException(500,"");
        }

        //判断错误信息
        if(StrUtil.isBlank(jsonObject.getString("access_token"))){
            if("40001".equals(jsonObject.getString("errcode"))){
                throw new CommonException(Integer.valueOf(jsonObject.getString("errcode")),"AppSecret错误或者AppSecret不属于这个公众号，请开发者确认AppSecret的正确性");
            }
            if("40002".equals(jsonObject.getString("errcode"))){
                throw new CommonException(Integer.valueOf(jsonObject.getString("errcode")),"请确保grant_type字段值为client_credential");
            }
            if("40164".equals(jsonObject.getString("errcode"))){
                throw new CommonException(Integer.valueOf(jsonObject.getString("errcode")),"调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置。（小程序及小游戏调用不要求IP地址在白名单内。）");
            }
            throw new CommonException(500,"获取微信accessToken失败");
        }
        String accessToken = jsonObject.getString("access_token");
        return accessToken;
    }

}
